from typing import List, Dict, Any
from enum import Enum
from .parser import ASTNode, ASTNodeType
from engine.catalog_manager import TableInfo, ColumnInfo

class PlanNodeType(Enum):
    """
    执行计划节点类型枚举。
    设计说明：覆盖所有支持的物理操作类型，便于后续扩展（如索引扫描、连接等）。
    """
    CREATE_TABLE = "CREATE_TABLE"
    INSERT = "INSERT"
    SEQ_SCAN = "SEQ_SCAN"
    FILTER = "FILTER"
    PROJECT = "PROJECT"
    DELETE = "DELETE"
    # TODO: 支持更多物理操作类型，如索引扫描、连接、聚合等

class PlanNode:
    """
    执行计划节点。
    属性说明：
      - node_type: 节点类型（物理操作类型）
      - properties: 节点属性（如表名、列名、条件等）
      - children: 子节点（用于表达操作树结构）
    设计决策：
      - 采用树结构表达复杂查询的物理执行顺序。
      - 支持递归打印，便于调试和优化分析。
    """
    def __init__(self, node_type: PlanNodeType, properties: Dict[str, Any] = None, children: List['PlanNode'] = None):
        self.node_type = node_type
        self.properties = properties or {}
        self.children = children or []
    
    def __str__(self, level=0):
        ret = "  " * level + f"{self.node_type}: {self.properties}\n"
        for child in self.children:
            ret += child.__str__(level + 1)
        return ret
    
    def __repr__(self):
        return self.__str__()
    
    def to_json(self):
        """输出JSON格式的执行计划"""
        import json
        return json.dumps(self.to_dict(), indent=2)
    
    def to_dict(self):
        """转换为字典格式"""
        # 处理properties中的复杂对象
        serializable_properties = {}
        for key, value in self.properties.items():
            if hasattr(value, '__dict__'):
                # 对于复杂对象，转换为字典
                if hasattr(value, 'name') and hasattr(value, 'type'):  # ColumnInfo对象
                    serializable_properties[key] = {
                        "name": value.name,
                        "type": value.type,
                        "length": getattr(value, 'length', None),
                        "nullable": getattr(value, 'nullable', True),
                        "primary_key": getattr(value, 'primary_key', False)
                    }
                elif hasattr(value, 'name') and hasattr(value, 'columns'):  # TableInfo对象
                    serializable_properties[key] = {
                        "name": value.name,
                        "columns": [
                            {
                                "name": col.name,
                                "type": col.type,
                                "length": getattr(col, 'length', None),
                                "nullable": getattr(col, 'nullable', True),
                                "primary_key": getattr(col, 'primary_key', False)
                            } for col in value.columns
                        ],
                        "primary_key": getattr(value, 'primary_key', [])
                    }
                else:
                    serializable_properties[key] = value.__dict__
            elif isinstance(value, list):
                # 处理列表中的复杂对象
                serializable_list = []
                for item in value:
                    if hasattr(item, '__dict__'):
                        if hasattr(item, 'name'):  # ColumnInfo对象
                            serializable_list.append({
                                "name": item.name,
                                "type": item.type,
                                "length": getattr(item, 'length', None),
                                "nullable": getattr(item, 'nullable', True),
                                "primary_key": getattr(item, 'primary_key', False)
                            })
                        else:
                            serializable_list.append(item.__dict__)
                    else:
                        serializable_list.append(item)
                serializable_properties[key] = serializable_list
            else:
                serializable_properties[key] = value
        
        return {
            "node_type": self.node_type.value,
            "properties": serializable_properties,
            "children": [child.to_dict() for child in self.children]
        }
    
    def to_s_expression(self):
        """输出S表达式格式"""
        if not self.children:
            return f"({self.node_type.value} {self.properties})"
        children_str = " ".join([child.to_s_expression() for child in self.children])
        return f"({self.node_type.value} {self.properties} {children_str})"

class Planner:
    """
    查询优化器与执行计划生成器。
    负责将语法树（AST）转换为物理执行计划（PlanNode树）。
    设计决策：
      - 支持多语句批量优化。
      - 采用分派模式，便于扩展新语句类型和优化规则。
      - 预留查询重写、索引选择、成本估算等扩展点。
    """
    def __init__(self):
        # TODO: 支持执行计划缓存（Plan Cache），提升重复查询性能
        pass
    
    def plan(self, ast_nodes: List[ASTNode]) -> List[PlanNode]:
        """
        主入口：将AST节点列表转换为执行计划列表。
        支持批量语句优化。
        """
        plans = []
        for node in ast_nodes:
            plan = self.plan_statement(node)
            plans.append(plan)
        return plans
    
    def plan_statement(self, node: ASTNode) -> PlanNode:
        """
        根据AST节点类型分派到具体计划生成方法。
        """
        if node.node_type == ASTNodeType.CREATE_TABLE:
            return self.plan_create_table(node)
        elif node.node_type == ASTNodeType.INSERT:
            return self.plan_insert(node)
        elif node.node_type == ASTNodeType.SELECT:
            return self.plan_select(node)
        elif node.node_type == ASTNodeType.DELETE:
            return self.plan_delete(node)
        # 新增支持 CREATE_DATABASE 和 USE_DATABASE，直接返回空计划或特殊计划节点
        elif node.node_type == ASTNodeType.CREATE_DATABASE:
            return PlanNode(PlanNodeType.CREATE_TABLE, {"database_name": node.value})
        elif node.node_type == ASTNodeType.USE_DATABASE:
            return PlanNode(PlanNodeType.CREATE_TABLE, {"use_database": node.value})
        else:
            raise ValueError(f"Unknown statement type: {node.node_type}")
    
    def plan_create_table(self, node: ASTNode) -> PlanNode:
        """
        生成 CREATE TABLE 的物理计划节点。
        """
        table_name = node.value
        columns = []
        for col_def in node.children:
            col_name = col_def.value["name"]
            col_type = col_def.value["type"]
            col_length = col_def.value.get("length")
            # 创建 ColumnInfo 实例，保持与 CatalogManager 的数据结构一致
            column_info = ColumnInfo(name=col_name, type=str(col_type.value) if hasattr(col_type, "value") else str(col_type), length=col_length)
            columns.append(column_info)
        # 创建 TableInfo 对象（此处暂不处理主键信息，使用空列表）
        table_info = TableInfo(name=table_name, columns=columns, primary_key=[])
    
        return PlanNode(
            PlanNodeType.CREATE_TABLE,
            {"table_info": table_info}
        )
    
    def plan_insert(self, node: ASTNode) -> PlanNode:
        """
        生成 INSERT 的物理计划节点。
        支持参数化与批量插入扩展。
        """
        table_name = node.value
        column_refs = []
        values = []
        for child in node.children:
            if child.node_type == ASTNodeType.COLUMN_REF:
                column_refs.append(child.value)
            elif child.node_type == ASTNodeType.VALUE:
                values.append(child.value)
        
        # 如果没有指定列，则使用所有列（实际应从Catalog获取列名）
        # 这里暂时使用占位符，实际执行时会从catalog获取正确的列名
        if not column_refs:
            column_refs = ["*"]  # 表示使用所有列
        
        return PlanNode(
            PlanNodeType.INSERT,
            {
                "table_name": table_name,
                "columns": column_refs,
                "values": values
            }
        )
    
    def plan_select(self, node: ASTNode) -> PlanNode:
        """
        生成 SELECT 的物理计划树。
        查询优化点：
          - 可在此处实现查询重写（如SELECT *重写为具体列名）。
          - 可分析WHERE条件，选择索引扫描或顺序扫描。
          - 可集成成本估算与物理计划选择（CBO）。
        """
        table_ref = None
        column_refs = []
        where_clause = None
        for child in node.children:
            if child.node_type == ASTNodeType.TABLE_REF:
                table_ref = child
            elif child.node_type == ASTNodeType.COLUMN_REF:
                column_refs.append(child.value)
            elif child.node_type == ASTNodeType.STAR:
                column_refs.append("*")
            elif child.node_type == ASTNodeType.BINARY_OP:
                where_clause = child
        table_name = table_ref.value if table_ref else "unknown"
        # 默认顺序扫描节点
        scan_node = PlanNode(
            PlanNodeType.SEQ_SCAN,
            {"table_name": table_name}
        )
        current_node = scan_node
        # WHERE优化：可在此处选择索引或重写为IN/UNION等
        if where_clause:
            # 保留条件的 AST，便于上层构建可执行的条件函数
            filter_node = PlanNode(
                PlanNodeType.FILTER,
                {"condition_ast": where_clause},
                [current_node]
            )
            current_node = filter_node
        # 投影节点（可重写SELECT *为具体列名，减少数据传输）
        project_node = PlanNode(
            PlanNodeType.PROJECT,
            {"columns": column_refs},
            [current_node]
        )
        return project_node
    
    def plan_delete(self, node: ASTNode) -> PlanNode:
        """
        生成 DELETE 的物理计划树。
        查询优化点：
          - 可分析WHERE条件，选择最优扫描方式。
          - 可批量删除优化。
        """
        table_ref = None
        where_clause = None
        for child in node.children:
            if child.node_type == ASTNodeType.TABLE_REF:
                table_ref = child
            elif child.node_type == ASTNodeType.BINARY_OP:
                where_clause = child
        table_name = table_ref.value if table_ref else "unknown"
        scan_node = PlanNode(
            PlanNodeType.SEQ_SCAN,
            {"table_name": table_name}
        )
        current_node = scan_node
        if where_clause:
            # 保留条件的 AST，便于上层构建可执行的条件函数
            filter_node = PlanNode(
                PlanNodeType.FILTER,
                {"condition_ast": where_clause},
                [current_node]
            )
            current_node = filter_node
        delete_node = PlanNode(
            PlanNodeType.DELETE,
            {"table_name": table_name},
            [current_node]
        )
        return delete_node
    
    def expression_to_string(self, node: ASTNode) -> str:
        """
        将表达式AST节点转换为字符串（用于物理计划条件表达）。
        设计说明：便于后续扩展为表达式树或谓词下推。
        """
        if node.node_type == ASTNodeType.BINARY_OP:
            left = self.expression_to_string(node.children[0])
            right = self.expression_to_string(node.children[1])
            op = node.value.value.lower().replace("_", " ")
            return f"({left} {op} {right})"
        elif node.node_type == ASTNodeType.COLUMN_REF:
            return node.value
        elif node.node_type == ASTNodeType.VALUE:
            if isinstance(node.value, str):
                return f"'{node.value}'"
            else:
                return str(node.value)
        else:
            return "unknown"
